package edu.isquen.util.factory;

import java.lang.reflect.Method;
import java.util.HashMap;
import com.jamonapi.proxy.MonProxyFactory;

import edu.isquen.core.base.service.BaseService;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ServiceFactory implements MethodInterceptor {

	private static ServiceFactory _application;

	private static HashMap<Class<?>, BaseService> _servicePool = new HashMap<Class<?>, BaseService>(100);

	private Enhancer enhancer = new Enhancer();

	private ServiceFactory() {
	}

	public static ServiceFactory getInstance() {
		if (_application == null) {
			_application = new ServiceFactory();
		}
		return _application;
	}

	public static BaseService createProcess(Class<?> iServiceClazz) throws ClassNotFoundException {
		BaseService service = (BaseService) _servicePool.get(iServiceClazz);
		if (service != null) {
			return service;
		}

		ServiceFactory factory = new ServiceFactory();
		
		Class<?>[] iclzs = new Class[] { iServiceClazz };
		String cn = iServiceClazz.getName();
		cn += "Impl";
		Class<?> clz = Class.forName(cn);

		service = (BaseService) MonProxyFactory.monitor(factory.getInstrumentedClass(iclzs, clz));

		_servicePool.put(iServiceClazz, service);

		return service;
	}

	public static BaseService createProcess(String clazzName) throws ClassNotFoundException {
		Class<?> iProcessClazz = Class.forName(clazzName);

		return createProcess(iProcessClazz);
	}

	public Object getInstrumentedClass(Class<?>[] iclzs, Class<?> clz) {
		enhancer.setInterfaces(iclzs);
		enhancer.setSuperclass(clz);
		enhancer.setCallback((Callback) this);
		return enhancer.create();
	}

	public Object intercept(Object o, Method method, Object[] methodParameters,
			MethodProxy methodProxy) throws Throwable {
		// TODO Auto-generated method stub
		if (method.getName().equals("finalize")) {
			return methodProxy.invokeSuper(o, methodParameters);
		}
		return methodProxy.invokeSuper(o, methodParameters);
	}

}
